package com.fos.BluetoothStory.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.UUID;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.fos.BluetoothStory.GlobalApplication;
import com.fos.BluetoothStory.data.TFMusicState;
import com.fos.BluetoothStory.model.MusicBean;
import com.fos.BluetoothStory.util.AppConstance;
import com.fos.BluetoothStory.util.BTRUtil;
import com.fos.BluetoothStory.util.ByteUtil;
import com.fos.BluetoothStory.util.CMD;
import com.fos.BluetoothStory.util.CommandUtil;
import com.fos.BluetoothStory.util.DeviceSongsCatch;

/**
 * This class does all the work for setting up and managing Bluetooth
 * connections with other devices. It has a thread that listens for
 * incoming connections, a thread for connecting with a device, and a
 * thread for performing data transmissions when connected.
 */
public class BluetoothChatService extends Service{
	public class MyBinder extends Binder{
        public BluetoothChatService getService(){
            return BluetoothChatService.this;
        }
    }
	
    // Debugging
    private static final String TAG = "BluetoothChatService";
    private static final boolean D = true;

    // Name for the SDP record when creating server socket
    private static final String NAME = BluetoothChatService.class.getName();

    // Unique UUID for this application
 	private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

 	//broadcast send info tag
 	public static final String BCS_STATE_CHANGE = "BCS_STATE_CHANGE";//连接状态
 	public static final String TOAST = "toast";
 	public static final String BCS_SONGS_UPDATE = "BCS_SONGS_UPDATE";//获取到歌曲信息
 	public static final String BCS_WORK_UPDATE = "BCS_READY_SWITCH_WORKMODE";//设备工作模式变更确定
 	public static final String BCS_STATE_PLAY_UPDATE = "BCS_STATE_PLAY_UPDATE";//设备工作模式变更确定
 	public static final String BCS_STATE_PLAY_UPDATE_DEVICE = "BCS_STATE_PLAY_UPDATE_DEVICE";//设备工作模式变更确定
 	
 	//broadcast flag
 	public static final String TOAST_FLAG = "TOAST_FLAG";
 	public static final String STATE_FLAG = "STATE_FLAG";
 	public static final String SONGS_UPDATE_PID = "SONGS_UPDATE_PID";
    
    // Member fields
    private BluetoothAdapter mAdapter;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;
    private MyBinder binder;
	private final LocalBroadcastManager lbm;

    // Constants that indicate the current connection state
    public static final int STATE_NONE = 0;       // we're doing nothing
    public static final int STATE_LISTEN = 1;     // now listening for incoming connections
    public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
    public static final int STATE_CONNECTED = 3;  // now connected to a remote device
    
    public BluetoothChatService() {
    	lbm = GlobalApplication.lbm;
	}
    
    @Override
    public void onCreate() {
    	super.onCreate();
    	
    	binder = new MyBinder();
    	mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        
        start();
    }
    
    @Override
	public IBinder onBind(Intent intent) {
		return binder;
	}

    /**
     * Set the current state of the chat connection
     * @param state  An integer defining the current connection state
     */
    private synchronized void setState(int state) {
        if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;

        // send the new state broadcast
        Intent stateIntent = new Intent(BCS_STATE_CHANGE);
        stateIntent.putExtra(STATE_FLAG, state);
        lbm.sendBroadcast(stateIntent);
    }

    /**
     * Return the current connection state. */
    public synchronized int getState() {
        return mState;
    }

    /**
     * Start the chat service. Specifically start AcceptThread to begin a
     * session in listening (server) mode. Called by the Activity onResume() */
    public synchronized void start() {
        if (D) Log.d(TAG, "start");

        // Cancel any thread attempting to make a connection
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

        // Cancel any thread currently running a connection
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        setState(STATE_LISTEN);
    }

    /**
     * Start the ConnectThread to initiate a connection to a remote device.
     * @param device  The BluetoothDevice to connect
     * @param secure Socket Security type - Secure (true) , Insecure (false)
     */
    public synchronized void connect(BluetoothDevice device) {
        if (D) Log.d(TAG, "connect to: " + device);

        // Cancel any thread attempting to make a connection
        if (mState == STATE_CONNECTING) {
            if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
        }

        // Cancel any thread currently running a connection
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // Start the thread to connect with the given device
        mConnectThread = new ConnectThread(device);
        mConnectThread.start();
        setState(STATE_CONNECTING);
    }

    /**
     * Start the ConnectedThread to begin managing a Bluetooth connection
     * @param socket  The BluetoothSocket on which the connection was made
     * @param device  The BluetoothDevice that has been connected
     */
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
        if (D) Log.d(TAG, "connected, Socket ");

        // Cancel the thread that completed the connection
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

        // Cancel any thread currently running a connection
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // Start the thread to manage the connection and perform transmissions
        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();

        new Thread(){
        	public void run() {
        		try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
        		if(D) Log.v("fan", "首次握手准备");
        		if (mConnectedThread != null) {
        			if(D) Log.v("fan", "首次握手");
        			mConnectedThread.write(CommandUtil.cShackCommand(1));//握手
        		}
        	};
        }.start();
    }

    /**
     * Stop all threads
     */
    public synchronized void stop() {
        if (D) Log.d(TAG, "stop");

        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        setState(STATE_NONE);
    }
    
    /**
	 * 在这里发送消息.
	 */
	public void sendMessage(byte[] message) {
		if (message == null) {
			return;
		}

		if (message.length < 1) {
			return;
		}

		//进行转义
		//Log.v("Before Escape: ", ByteUtil.byte2hex(message,true));

        String msg = ByteUtil.byte2hex(message,true);
        message = ByteUtil.hex2byte("11 " + msg
                        .substring(3,msg.length()-3)
                        .replaceAll(" 13"," 13 26")
                        .replaceAll(" 12"," 13 25")
                        .replaceAll(" 11"," 13 24") + "12");

        Log.e("After Escape: ", ByteUtil.byte2hex(message,true));

		// 通知 BluetoothService 写入字节数组
		write(message);
	}

    /**
     * Write to the ConnectedThread in an unsynchronized manner
     * @param out The bytes to write
     * @see ConnectedThread#write(byte[])
     */
    public void write(byte[] out) {
        // Create temporary object
        ConnectedThread r;
        // Synchronize a copy of the ConnectedThread
        synchronized (this) {
            if (mState != STATE_CONNECTED) return;
            r = mConnectedThread;
        }
        // Perform the write unsynchronized
        r.write(out);
    }

    /**
     * Indicate that the connection attempt failed and notify the UI Activity.
     */
    private void connectionFailed() {
        // Send a failure message broadcast
        Intent toastIntent = new Intent(TOAST);
        toastIntent.putExtra(TOAST_FLAG, "无法连接该蓝牙设备");
        lbm.sendBroadcast(toastIntent);

        // Start the service over to restart listening mode
        BluetoothChatService.this.start();
    }

    /**
     * Indicate that the connection was lost and notify the UI Activity.
     */
    private void connectionLost() {
        // Send a failure message broadcast
        Intent toastIntent = new Intent(TOAST);
        toastIntent.putExtra(TOAST_FLAG, "蓝牙连接已断开");
        lbm.sendBroadcast(toastIntent);

        // Start the service over to restart listening mode
        BluetoothChatService.this.start();
    }

    /**
     * This thread runs while attempting to make an outgoing connection
     * with a device. It runs straight through; the connection either
     * succeeds or fails.
     */
    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        public ConnectThread(BluetoothDevice device) {
            mmDevice = device;
            BluetoothSocket tmp = null;

            // Get a BluetoothSocket for a connection with the given BluetoothDevice
            try {
                if (android.os.Build.VERSION.SDK_INT >= 10){
                    tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
                }else{
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
                }
				Log.i(TAG, "createRfcommSocketToServiceRecord success!");
            } catch (IOException e) {
                Log.e(TAG, "Socket : create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectThread ");
            setName("ConnectThread");

            // Always cancel discovery because it will slow down a connection
            mAdapter.cancelDiscovery();

            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                mmSocket.connect();
            } catch (IOException e) {
                // Close the socket
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() socket during connection failure", e2);
                }
                connectionFailed();
                return;
            }

            // Reset the ConnectThread because we're done
            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            // Start the connected thread
            connected(mmSocket, mmDevice);
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }

    /**
     * This thread runs during a connection with a remote device.
     * It handles all incoming and outgoing transmissions.
     */
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread: ");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the BluetoothSocket input and output streams
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);
                    
                    StringBuffer sb = new StringBuffer("");
					for (int i = 0; i < bytes; i++) {
						String tmp = buffer[i] < 0 ? Integer
								.toHexString(buffer[i] + 256) + "" : Integer
								.toHexString(buffer[i]) + "";
						sb.append(tmp.length() > 1 ? tmp : "0" + tmp);
					}
					String result = sb.toString();
					result = result.replaceAll("1324", "11");
					result = result.replaceAll("1325", "12");
					result = result.replaceAll("1326", "13");
					doCheck(result);
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    // Start the service over to restart listening mode
                    BluetoothChatService.this.start();
                    break;
                }
            }
        }
        
        // 执行不同的操作
 		private void doCheck(String res) {
 			String cmd = BTRUtil.getCmd(res).toLowerCase(); // 将命令编码转换为小写
 			if(D) Log.i("fan", "in " + cmd + "," + res);

 			// 如果收到蓝牙命令不是确认命令，首先回复确认
 			int cmdInt = Integer.parseInt(cmd, 16);
 			boolean cmdFlag = false;
 			boolean isSure = true;

             // 0000 0010  回首 02
             // 0000 1010  回中 0a
             // 0001 0010  回结 12
             if (res.substring(8,10).equals("02") ||
                     res.substring(8,10).equals("0a") ||
                     res.substring(8,10).equals("12") ){

                 if (!res.substring(10,12).equals("55")){
                	 if(D) Log.i("fan","包确认符不是正确！");
                	 isSure = false;
                 }
             }else{
                 write(CommandUtil.cMakeResponse((byte) cmdInt));
                 cmdFlag = true;
             }

 			switch (cmdInt) {

 			case 1:
 				break;
 			case 2:
 				if(cmdFlag){
 					// 02,112e000200280028292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4fa40912
 					// BluetoothService.sendMessage(CommandUtil.cShakeHands(false));
 					int startCmd = Integer.parseInt(res.substring(14, 16), 16);
 					CommandUtil.setStartCMD(startCmd);
 					if(D) Log.i("fan", "握手成功startCmd="+startCmd);
 					setState(STATE_CONNECTED);
 					
 					sendMessage(CommandUtil.cMakeCommand(CMD.BTR_GET_STDB_MODE, (byte) 0x00, false));
 					
 					// 获取设备电压(仅在连接成功后获取一次)
 					sendMessage(CommandUtil.cGetVoltage());

 					// 获取蓝牙信号(仅在连接成功后获取一次)
 					sendMessage(CommandUtil.cGetSignal());
 					
// 					sendMessage(CommandUtil.queryPlayState());
 				}
 				break;
 			default:
 				if(cmdInt >= CommandUtil.startCmd){
 					if(D) Log.i("fan","请求接口回调cmdint="+(cmdInt-CommandUtil.startCmd));
 					switch ((cmdInt-CommandUtil.startCmd)) {
 						case CMD.BTR_SET_VOL://设置音量
 							if (!cmdFlag && isSure) {
 								int volume = Integer.parseInt(res.substring(12, 14), 16);
 								TFMusicState.getInstance().setVolume(volume);
 							}
 							break;
 						case CMD.BTR_SET_PLAY_STATUS:
 							if (res.contains("55")) {
 								sendMessage(CommandUtil.queryPlayState());
 							} else {
 								boolean isPause = CommandUtil.cGetPlayPauseState(res);
 								AppConstance.setIsPlayOrPause(!isPause);
 								if(D) Log.i("fan",res+"音箱按键播放"+AppConstance.isPlayOrPause());
 								// 音箱按键控制本地播放是否暂停
 								lbm.sendBroadcast(new Intent(BCS_STATE_PLAY_UPDATE_DEVICE));
 							}
 							break;
 						case CMD.BTR_GET_PLAY_STATUS://查询播放状态
 							if (!cmdFlag && isSure) {
 								int i = Integer.parseInt(res.substring(13, 14));
 								if(D) Log.i("fan","播放状态"+i);
 								AppConstance.setIsPlayOrPause(i!=0);
 								lbm.sendBroadcast(new Intent(BCS_STATE_PLAY_UPDATE));
 							}
 							break;
 						case CMD.BTR_SET_PLAY_MUSICID:
// 							write(CommandUtil.cMakeResponse((byte) cmdInt));
 							if(D) Log.i("fan","播放歌曲 cmdFlag="+cmdFlag+";isSure="+isSure);
 							break;
 						case CMD.BTR_GET_STDB_MODE://获取系统工作模式
 							String mode = res.substring(12,14);
 							if(D) Log.i("fan", "系统模式 res="+res+";mode="+mode);
 							int imd = Integer.valueOf(mode);
 							AppConstance.sPlayState = imd;
 							break;
						case CMD.BTR_SWITCH_MODE://改变系统工作模式
			                if (!cmdFlag){
			                    //这是回应指令 播放的请求得到确认
			                    if (isSure){
			                    	//TODO 根据当前工作模式，判断是否停止相应播放
			                    	Intent palyMode = new Intent(BCS_WORK_UPDATE);
			                    	lbm.sendBroadcast(palyMode);
			                    }else{
			                        //不是55那就是有错，AA或者AB或者AC
			                        //AB有错的话要告诉主界面弹错误
			                        if (res.substring(10,12).equals("ab")){
			                            Intent intent = new Intent(TOAST);
			                            intent.putExtra(TOAST_FLAG, "模式切换失败");
			                            lbm.sendBroadcast(intent);
			                        }
			                    }
			                    //回应指令不参与下一步解析
			                    return;
			                }
			                if(D) Log.i("fan", "SWITCH_MODE res="+res);
							// 28,1107002800010003330012 OR 28,11070028000100ff2f0112 OR
							// 28,1107002800010000300112
							String str = res.substring(15, 16);
							switch (str) {
								case "3":// 如果是切换到T卡播放
									AppConstance.sPlayState = 3;
									break;
								case "1":// 如果是切换到U盘播放
									AppConstance.sPlayState = 1;
									break;
								case "0":// 如果是切换到音箱播放
									AppConstance.sPlayState = 0;
									break;
								case "2":// 如果是切换到LINE IN播放
									AppConstance.sPlayState = 2;
									break;
								default:
									break;
							}
							if(AppConstance.sPID > 0){//获取歌曲信息
								sendMessage(CommandUtil.cgetListMusic(new byte[] {
										(byte) AppConstance.sPID, (byte) 0x00, (byte) 12, (byte) 0x00}));
							}
							break;
						case CMD.BTR_SEND_MUSIC_LIST://多了一个目录数据，与原来的不同
							if(!cmdFlag)
								break;
							
							MusicBean mb = new MusicBean();
							mb.pid = Integer.parseInt(BTRUtil.cGetMusicPNo(res), 16);
							mb.id = Integer.parseInt(BTRUtil.cGetMusicNo(res), 16);
							mb.title = BTRUtil.unicodeToString(BTRUtil.cGetMusicName(res));
//							if(D) Log.i("fan", "song res="+res);
							if(D) Log.i("fan", "song pid"+mb.pid+";id="+mb.id+";title="+mb.title);
							if(DeviceSongsCatch.put(mb)){
								Intent songIntent = new Intent(BCS_SONGS_UPDATE);
								songIntent.putExtra(SONGS_UPDATE_PID, mb.pid);
								lbm.sendBroadcast(songIntent);
							}
							break;
						default:
							break;
					}
 				}
 			}
 		}

        /**
         * Write to the connected OutStream.
         * @param buffer  The bytes to write
         */
        public void write(byte[] buffer) {
            try {
                mmOutStream.write(buffer);
                mmOutStream.flush();
                if(D) Log.v("fan", "发消息"+Arrays.toString(buffer));
            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
                setState(STATE_NONE);
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
	
}
